package com.java.mongodbtest.service;

import com.java.mongodbtest.entity.Comment;
import com.java.mongodbtest.repository.CommentRepository;
import com.java.mongodbtest.utils.IdUtils;
import com.mongodb.connection.QueryResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;


import javax.annotation.Resource;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import java.util.regex.Pattern;

/**
 * @author huxb
 * @date 2020/9/18 0018 下午 2:01
 * @Desciption
 */
@Service
public class CommentService {

    @Resource
    private CommentRepository commentRepository;

    @Autowired
    private MongoTemplate mongoTemplate;
    /**
     * 查询所有
     * @return
     */
    public List<Comment> findAll() {
         return    commentRepository.findAll();
    }

    /**
     * 根据id查询
     * @param id
     * @return
     */
    public Comment findDetailById(String id) {
        return commentRepository.findById(id).orElse(null);
    }

    /**
     * 保存
     * @param comment
     */
    public void save(Comment comment) {
        comment.set_id(IdUtils.newId());
        comment.setThumbup(0);
        comment.setPublishdate(new Date());
        commentRepository.save(comment);
    }

    /**
     * 修改
     * @param comment
     */
    public void update(Comment comment) {
        commentRepository.save(comment);
    }

    /**
     * 删除
     * @param id
     */
    public void delete(String id) {
        commentRepository.deleteById(id);
    }

    public List<Comment> findByArticleId(String articleId) {
      return   commentRepository.findByArticleid(articleId);
    }

    /**
     * 分页查询
     * @param pageSize
     * @param pageNumber
     * @param conent
     * @param userId
     * @param startThumbup
     * @param endThumbup
     * @return
     */
    public  Page<Comment>  findPageBy(Integer pageSize, Integer pageNumber, String conent, String userId, Integer startThumbup, Integer endThumbup) {
        List<Comment> commentlist = new ArrayList<>();

        //用来封装所有条件的对象
        Query query = new Query();
        //用来构建条件
        Criteria criteria = new Criteria();
        /**
         * 这里使用的正则表达式的方式
         * 第二个参数Pattern.CASE_INSENSITIVE是对字符大小写不明感匹配
         */
        Pattern pattern = Pattern.compile("^.*"+ conent +".*$", Pattern.CASE_INSENSITIVE);
        /**
         *  criteria.and().regex() 在这里是构建了一个模糊查询的条件，并且用 'and' 相连
         *  query.addCriteria 把条件封装起来
         */
        if (conent != null) {
            query.addCriteria(criteria.and("content").regex(pattern));
        }

        if (userId  != null) {
            /**精准查询的条件
             *  criteria.and().is() 在这里是构建了一个精准查询的条件，并且用 'and' 相连
             *  query.addCriteria 把条件封装起来
             */
            query.addCriteria(criteria.and("userid").is(userId));
        }

//        if (endThumbup != null && startThumbup != null ) {
//            /**
//             * 在某个值之间的条件（类似于sql中的BETWEEN ... AND）
//             * 如果在这里，模仿精准查询，把 is() 方法换成 gt() 或 lt() ，然后运行，肯定会报错，具体的错误
//             */
//            //大于方法
//            Criteria gte = Criteria.where("thumbup").gte(startThumbup);
//            //小于方法
//            Criteria lte = Criteria.where("thumbup").lte(endThumbup);
//            /**
//             * new Criteria().andOperator(gt,lt) 把上面的大于和小于放在一起，注意上面两个key一定是一样的
//             * andOperator() 这个方法就是关键的方法了，把同key的多个条件组在一起
//             * 但是 andOperator() 有个很坑的地方就是，在一个query中只能出现一次
//             * 如果你有很固定很明确的入参，那还好，直接调用一次 andOperator()
//             * 如果是多个key需要多个条件，而且条件数量还是动态的，怕不是魔鬼吧...
//             */
//            query.addCriteria(new Criteria().andOperator(gte, lte));
//        }
        /**
         * 当得知一个query中只能存在一个 andOperator() 方法的时候，就应该把思考方向放在如何
         *
         * 把不确定个数的 Criteria 对象放入一个 andOperator() 方法中，这里是把多个 Criteria 对象用逗号分隔的，其实 andOperator() 方法还可以入参 Criteria[] 数组
         */

        //定义一个泛型集合，类型为 Criteria
        List<Criteria> criteriaList = new ArrayList<>();
        //定义一个无长度的数组，类型为 Criteria
        Criteria[] criteriaArray = {};
        //往集合里面添加条件对象
        if(startThumbup != null && endThumbup != null){
            //大于方法
            Criteria gt = Criteria.where("thumbup").gt(startThumbup);
            //小于方法
            Criteria lt = Criteria.where("thumbup").lt(endThumbup);
            if(gt!=null && lt!=null){
                criteriaList.add(gt);
                criteriaList.add(lt);
            }else if(gt!=null){
                query.addCriteria(gt);
            }else if(lt!=null){
                query.addCriteria(lt);
            }
        }
        //是否有条件
        if(criteriaList.size()>0){
            //把无长度的数组实例出来，长度就位集合的个数
            criteriaArray = new Criteria[criteriaList.size()];
            for(int i = 0 ; i < criteriaList.size() ; i++){
                //把集合中的条件对象全部存入数组中
                criteriaArray[i] = criteriaList.get(i);
            }
        }
        //最后把数组入参到 andOperator() 方法中
//        query.addCriteria(new Criteria().andOperator(criteriaArray));


        if (pageNumber == null) {
            pageNumber = 1;
        }
        if (pageSize == null) {
            pageSize = 2;
        }

        Pageable pageable = PageRequest.of(pageNumber, pageSize);
        List<Comment> commentList = mongoTemplate.find(query.with(pageable), Comment.class);

    Page<Comment> page = PageableExecutionUtils.getPage(commentList, pageable, () -> mongoTemplate.count(query, Comment.class));
        return page;
    }

    /**
     * 修改
     * @param id
     */
    public void thumbup(String id) {
        //修改条件
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(id));
        //修改的数据
        Update update = new Update();
        //在原来的基础上加一
        update.inc("thumbup", 1);
        mongoTemplate.updateFirst(query, update, "comment");
    }
}
